//! Windows Event Log Appender
//!
//! 将 FATAL 级别日志写入 Windows Event Log。
//!
//! ## 功能
//!
//! - 使用 windows-sys 的 Win32_System_EventLog API
//! - 动态 Source Name，无需预注册 Event Source
//! - 同步写入确保进程崩溃前完成
//!
//! ## 示例
//!
//! ```rust,ignore
//! use log4r::appender::syslog::windows::WindowsEventLog;
//! use log4r::appender::syslog::SyslogAppender;
//! use log4r::{LogEvent, Level};
//!
//! let appender = WindowsEventLog::new("my_app");
//! let event = LogEvent::new(Level::Fatal, "my_app", "严重错误");
//! appender.write_syslog(&event).ok();
//! ```

use crate::error::Log4rError;
use crate::event::LogEvent;

use super::SyslogAppender;

use windows_sys::Win32::System::EventLog::{
    DeregisterEventSource, RegisterEventSourceW, ReportEventW, EVENTLOG_ERROR_TYPE,
};

/// Windows Event Log Appender
///
/// 将 FATAL 级别日志写入 Windows Event Log。
/// 使用动态 Source Name，无需预注册 Event Source。
///
/// ## 线程安全
///
/// `WindowsEventLog` 实现 `Send + Sync`，可以安全地在线程间共享。
/// - `source_name` 是 `String`，本身是 `Send + Sync`
/// - 没有内部可变状态
///
/// ## 示例
///
/// ```rust,ignore
/// use log4r::appender::syslog::windows::WindowsEventLog;
/// use log4r::appender::syslog::SyslogAppender;
///
/// let appender = WindowsEventLog::new("my_app");
/// assert_eq!(appender.name(), "WindowsEventLog");
/// ```
pub struct WindowsEventLog {
    /// 事件源名称（app_name）
    source_name: String,
}

// WindowsEventLog 是 Send + Sync 安全的
// - source_name 是 String，本身是 Send + Sync
// - 没有内部可变状态
// - Windows API 调用是线程安全的（每次调用独立注册/注销句柄）
unsafe impl Send for WindowsEventLog {}
unsafe impl Sync for WindowsEventLog {}

impl WindowsEventLog {
    /// 创建新的 Windows Event Log Appender
    ///
    /// # Arguments
    ///
    /// * `app_name` - 应用名称，用作事件源标识
    ///
    /// # Returns
    ///
    /// 返回新的 `WindowsEventLog` 实例
    ///
    /// # 示例
    ///
    /// ```rust,ignore
    /// use log4r::appender::syslog::windows::WindowsEventLog;
    ///
    /// let appender = WindowsEventLog::new("my_app");
    /// ```
    pub fn new(app_name: &str) -> Self {
        Self {
            source_name: app_name.to_string(),
        }
    }

    /// 获取事件源名称
    ///
    /// # Returns
    ///
    /// 返回事件源名称的引用
    pub fn source_name(&self) -> &str {
        &self.source_name
    }

    /// 格式化日志消息
    ///
    /// 格式: `{timestamp} [{level}] {target}: {message}`
    ///
    /// # Arguments
    ///
    /// * `event` - 日志事件
    ///
    /// # Returns
    ///
    /// 格式化后的消息字符串
    fn format_message(&self, event: &LogEvent) -> String {
        // 使用 RFC3339 格式化时间戳，失败时使用默认格式
        let timestamp = event
            .timestamp
            .format(&time::format_description::well_known::Rfc3339)
            .unwrap_or_else(|_| event.timestamp.to_string());

        format!(
            "{} [{}] {}: {}",
            timestamp, event.level, event.target, event.message
        )
    }
}

impl SyslogAppender for WindowsEventLog {
    /// 同步写入 Windows Event Log
    ///
    /// # Arguments
    ///
    /// * `event` - 要写入的日志事件
    ///
    /// # Returns
    ///
    /// * `Ok(())` - 写入成功
    /// * `Err(Log4rError::AppenderError)` - 写入失败
    ///
    /// # Safety
    ///
    /// 此方法内部使用 unsafe 代码调用 Windows API：
    /// - `RegisterEventSourceW`: 注册事件源，返回句柄
    /// - `ReportEventW`: 写入事件日志
    /// - `DeregisterEventSource`: 释放句柄
    ///
    /// 所有指针在函数调用期间有效，句柄在使用后立即释放。
    fn write_syslog(&self, event: &LogEvent) -> Result<(), Log4rError> {
        // 验证 app_name 非空
        if self.source_name.is_empty() {
            return Err(Log4rError::AppenderError {
                name: "WindowsEventLog".to_string(),
                cause: "app_name 不能为空".to_string(),
            });
        }

        let message = self.format_message(event);

        // 转换为宽字符串（UTF-16，以 null 结尾）
        let source_wide: Vec<u16> = self
            .source_name
            .encode_utf16()
            .chain(std::iter::once(0))
            .collect();
        let message_wide: Vec<u16> = message.encode_utf16().chain(std::iter::once(0)).collect();

        // SAFETY: 调用 Windows API
        // - RegisterEventSourceW: 注册事件源，返回句柄
        //   - 第一个参数为 null 表示本地计算机
        //   - 第二个参数是以 null 结尾的宽字符串指针
        // - ReportEventW: 写入事件日志
        //   - handle: 有效的事件源句柄
        //   - wType: EVENTLOG_ERROR_TYPE 表示错误级别
        //   - wCategory: 0 表示无类别
        //   - dwEventID: 0 表示默认事件 ID
        //   - lpUserSid: null 表示无用户 SID
        //   - wNumStrings: 1 表示一个字符串
        //   - dwDataSize: 0 表示无附加数据
        //   - lpStrings: 指向字符串指针数组
        //   - lpRawData: null 表示无原始数据
        // - DeregisterEventSource: 释放句柄
        // 所有指针在函数调用期间有效
        unsafe {
            let handle = RegisterEventSourceW(std::ptr::null(), source_wide.as_ptr());

            if handle.is_null() {
                return Err(Log4rError::AppenderError {
                    name: "WindowsEventLog".to_string(),
                    cause: "RegisterEventSourceW 失败".to_string(),
                });
            }

            let strings = [message_wide.as_ptr()];
            // 使用 Event ID 1000 避免显示系统默认消息
            // Event ID 0 会导致 Windows 显示 "操作成功完成。" 而不是实际消息
            let result = ReportEventW(
                handle,
                EVENTLOG_ERROR_TYPE,  // 事件类型：错误
                0,                    // 事件类别
                1000,                 // 事件 ID（非零值，避免系统默认消息）
                std::ptr::null_mut(), // 用户 SID (PSID)
                1,                    // 字符串数量
                0,                    // 数据大小
                strings.as_ptr(),     // 字符串数组
                std::ptr::null_mut(), // 数据
            );

            DeregisterEventSource(handle);

            if result == 0 {
                return Err(Log4rError::AppenderError {
                    name: "WindowsEventLog".to_string(),
                    cause: "ReportEventW 失败".to_string(),
                });
            }
        }

        Ok(())
    }

    fn name(&self) -> &'static str {
        "WindowsEventLog"
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::level::Level;

    // UT-8.1-001: 测试 WindowsEventLog::new() 创建 (AC: 8.1.2)
    #[test]
    fn test_windows_event_log_new() {
        // GIVEN: 应用名称
        let app_name = "test_app";

        // WHEN: 创建 WindowsEventLog
        let appender = WindowsEventLog::new(app_name);

        // THEN: source_name 应正确设置
        assert_eq!(appender.source_name(), "test_app");
    }

    // UT-8.1-002: 测试消息格式化包含所有字段 (AC: 8.1.4)
    #[test]
    fn test_format_message_contains_all_fields() {
        // GIVEN: WindowsEventLog 和 LogEvent
        let appender = WindowsEventLog::new("my_app");
        let event = LogEvent::new(Level::Fatal, "my_app::module", "严重错误消息");

        // WHEN: 格式化消息
        let message = appender.format_message(&event);

        // THEN: 消息应包含所有字段
        // 格式: {timestamp} [{level}] {target}: {message}
        assert!(message.contains("[FATAL]"), "应包含级别: {}", message);
        assert!(
            message.contains("my_app::module"),
            "应包含 target: {}",
            message
        );
        assert!(message.contains("严重错误消息"), "应包含消息: {}", message);
        // 时间戳应为 RFC3339 格式（包含 T 和时区）
        assert!(
            message.contains("T") || message.contains("-"),
            "应包含时间戳: {}",
            message
        );
    }

    // UT-8.1-003: 测试事件级别为 EVENTLOG_ERROR_TYPE (AC: 8.1.3)
    #[test]
    fn test_event_type_is_error() {
        // GIVEN: EVENTLOG_ERROR_TYPE 常量
        // WHEN: 检查值
        // THEN: 应为 1（Windows 定义的错误类型）
        assert_eq!(EVENTLOG_ERROR_TYPE, 1);
    }

    // UT-8.1-004: 测试 SyslogAppender trait 实现 (AC: 8.1.1)
    #[test]
    fn test_syslog_appender_trait_implementation() {
        // GIVEN: WindowsEventLog
        let appender = WindowsEventLog::new("test_app");

        // WHEN: 调用 trait 方法
        let name = appender.name();

        // THEN: 应返回正确的名称
        assert_eq!(name, "WindowsEventLog");
    }

    // UT-8.1-005: 测试 WindowsEventLog 是 Send + Sync
    #[test]
    fn test_windows_event_log_is_send_sync() {
        // GIVEN: WindowsEventLog
        // WHEN: 检查 Send + Sync
        // THEN: 编译通过即验证成功
        fn assert_send<T: Send>() {}
        fn assert_sync<T: Sync>() {}

        assert_send::<WindowsEventLog>();
        assert_sync::<WindowsEventLog>();
    }

    // UT-8.1-006: 测试空应用名称创建成功但写入失败
    #[test]
    fn test_empty_app_name() {
        // GIVEN: 空应用名称
        let appender = WindowsEventLog::new("");

        // THEN: 创建应成功
        assert_eq!(appender.source_name(), "");
    }

    // UT-8.1-009: 测试空应用名称写入时返回错误
    #[test]
    fn test_empty_app_name_write_returns_error() {
        // GIVEN: 空应用名称的 Appender
        let appender = WindowsEventLog::new("");
        let event = LogEvent::new(Level::Fatal, "test", "测试消息");

        // WHEN: 尝试写入
        let result = appender.write_syslog(&event);

        // THEN: 应返回错误
        assert!(result.is_err());
        if let Err(err) = result {
            assert!(err.to_string().contains("app_name"));
        }
    }

    // UT-8.1-007: 测试 Unicode 应用名称
    #[test]
    fn test_unicode_app_name() {
        // GIVEN: Unicode 应用名称
        let appender = WindowsEventLog::new("日志应用");

        // THEN: 应正确保存
        assert_eq!(appender.source_name(), "日志应用");
    }

    // UT-8.1-008: 测试消息格式化 Unicode 内容
    #[test]
    fn test_format_message_unicode() {
        // GIVEN: Unicode 内容的 LogEvent
        let appender = WindowsEventLog::new("测试");
        let event = LogEvent::new(Level::Fatal, "日志::模块", "错误消息 🚀");

        // WHEN: 格式化消息
        let message = appender.format_message(&event);

        // THEN: Unicode 应正确保存
        assert!(message.contains("日志::模块"));
        assert!(message.contains("🚀"));
    }

    // 注意：实际的 Windows Event Log 写入测试需要在 Windows 系统上运行
    // 并且可能需要管理员权限，因此标记为 #[ignore]
    #[test]
    #[ignore]
    fn test_write_syslog_integration() {
        // GIVEN: WindowsEventLog 和 FATAL 事件
        let appender = WindowsEventLog::new("log4r_test");
        let event = LogEvent::new(Level::Fatal, "log4r::test", "集成测试消息");

        // WHEN: 写入系统日志
        let result = appender.write_syslog(&event);

        // THEN: 应成功（在 Windows 上）
        // 注意：可能因权限问题失败
        println!("写入结果: {:?}", result);
    }
}
